{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "separated-license",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "origin\tgit@github.com:ustchope/dlwpn.git (fetch)\n",
      "origin\tgit@github.com:ustchope/dlwpn.git (push)\n",
      "[master 77a58d6] 更新ch6 #1 change 2021-07027\n",
      " 1 file changed, 105 insertions(+), 101 deletions(-)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "To github.com:ustchope/dlwpn.git\n",
      "   6f9b694..77a58d6  master -> master\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "# 增加更新\n",
    "git add ch6.ipynb\n",
    "\n",
    "git remote -v\n",
    "\n",
    "git commit -m '更新ch6 #1 change 2021-07027'\n",
    "\n",
    "git push origin master"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "atmospheric-shoulder",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "time: 5.06 s (started: 2021-07-25 22:44:55 +08:00)\n"
     ]
    }
   ],
   "source": [
    "# 自动计算cell的计算时间\n",
    "%load_ext autotime\n",
    "\n",
    "#设置使用的gpu\n",
    "import tensorflow as tf\n",
    "\n",
    "gpus = tf.config.list_physical_devices(\"GPU\")\n",
    "\n",
    "if gpus:\n",
    "   \n",
    "    gpu0 = gpus[2] #如果有多个GPU，仅使用第0个GPU\n",
    "    tf.config.experimental.set_memory_growth(gpu0, True) #设置GPU显存用量按需使用\n",
    "    # 或者也可以设置GPU显存为固定使用量(例如：4G)\n",
    "    #tf.config.experimental.set_virtual_device_configuration(gpu0,\n",
    "    #    [tf.config.experimental.VirtualDeviceConfiguration(memory_limit=4096)]) \n",
    "    tf.config.set_visible_devices([gpu0],\"GPU\") "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "cutting-collection",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "time: 13.8 ms (started: 2021-07-25 22:45:05 +08:00)\n"
     ]
    }
   ],
   "source": [
    "%config InlineBackend.figure_format='svg' #矢量图设置，让绘图更清晰"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "proof-caution",
   "metadata": {},
   "source": [
    "# 机器学习的通用工作流程"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "green-commonwealth",
   "metadata": {},
   "source": [
    "**本章涵盖**\n",
    "* 构建机器学习问题的步骤\n",
    "* 开发工作模型的步骤\n",
    "* 在生产中部署模型并对其进行维护的步骤"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "closing-drove",
   "metadata": {},
   "source": [
    "我们之前的例子假设我们已经有了一个标记的数据集，我们可以立即开始训练模型。 在现实世界中，情况往往并非如此。 您不是从数据集开始，而是从问题开始。\n",
    "\n",
    "想象一下，您正在开办自己的机器学习咨询店。 你合并，你建立一个漂亮的网站，你通知你的网络。 项目开始滚滚而来。\n",
    "* 用于图片共享社交网络的个性化照片搜索引擎——输入“婚礼”，即可检索您在婚礼上拍摄的所有照片，无需任何手动标记。\n",
    "* 在新兴聊天应用程序的帖子中标记垃圾邮件和攻击性文本内容。\n",
    "* 为在线广播用户构建音乐推荐系统。\n",
    "* 检测电子商务网站的信用卡欺诈。\n",
    "* 预测展示广告点击率，以决定在给定时间向给定用户投放哪个广告。\n",
    "* 在饼干生产线的传送带上标记异常饼干。\n",
    "* 使用卫星图像预测未知考古遗址的位置。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "orange-plasma",
   "metadata": {},
   "source": [
    "**道德注意事项**\n",
    "> 有时可能会向您提供道德上可疑的项目，例如“构建一个 AI，根据某人的面部照片对某人的可信度进行评级”。首先，该项目的有效性存在疑问：不清楚为什么可信度会反映在某人的脸上。其次，这样的任务为各种伦理问题打开了大门。为这项任务收集数据集相当于记录标记图片的人的偏见和偏见。您将在此类数据上训练的模型仅仅是\n",
    "将这些相同的偏见编码到一个黑盒算法中，这会给它们一个薄薄的合法性外衣。在像我们这样的技术文盲社会，“人工智能算法说这个人不可信”似乎比“约翰·史密斯说这个人不可信”更具有分量和客观性——尽管前者是对后者。你的模型将大规模清洗和操作人类判断最糟糕的方面，对真实人的生活产生负面影响。\n",
    "\n",
    "> 技术从来都不是中立的。如果你的工作对世界有任何影响，那么这种影响有一个道德方向：技术选择也是道德选择。始终慎重考虑您希望工作支持的价值观。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bigger-blank",
   "metadata": {},
   "source": [
    "如果您可以从 keras.datasets 导入正确的数据集并开始拟合一些深度学习模型，那将非常方便。 不幸的是，在现实世界中，您必须从头开始。\n",
    "\n",
    "在本章中，您将了解可用于处理和解决任何机器学习问题（如上面列出的问题）的通用分步蓝图。 该模板将汇集并巩固您在第 4 章和第 5 章中学到的所有内容，并将为您提供更广泛的背景信息，以作为您将在下一章中学习的内容的基础。\n",
    "\n",
    "机器学习的通用工作流程大致分为三个部分：\n",
    "\n",
    "* 定义任务：了解问题域和客户要求背后的业务逻辑。 收集数据集，了解数据代表什么，并选择衡量任务成功的方式。\n",
    "* 开发模型：准备数据以便机器学习模型可以处理它，选择模型评估协议和简单的基线来击败，训练第一个具有泛化能力的模型，该模型可能会过度拟合，然后对模型进行正则化和调整，直到 您可以实现最佳的泛化性能。\n",
    "* 部署模型：向利益相关者展示您的工作，将模型发送到 Web 服务器、移动应用程序、网页或嵌入式设备，在野外监控模型的性能，并开始收集您需要构建的数据 下一代模型。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "innocent-keyboard",
   "metadata": {},
   "source": [
    "让我们深入了解。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "champion-librarian",
   "metadata": {},
   "source": [
    "## 定义任务"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "worth-cardiff",
   "metadata": {},
   "source": [
    "如果不深入了解您所做工作的背景，您就无法做好工作。 为什么您的客户试图解决这个特定问题？ 他们将从解决方案中获得什么价值——您的模型将如何使用，它将如何适应您客户的业务流程？ 什么样的数据是可用的，或者可以收集？ 什么样的机器学习任务可以映射到业务问题？"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "brazilian-tunisia",
   "metadata": {},
   "source": [
    "### 框定问题"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "biblical-benjamin",
   "metadata": {},
   "source": [
    "构建机器学习问题通常涉及与利益相关者的许多详细讨论。 以下是您应该首先考虑的问题。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "hollow-lemon",
   "metadata": {},
   "source": [
    "* 你的输入数据是什么？ 你想预测什么？ 如果您有可用的训练数据，您只能学习预测某些内容：例如，如果您同时拥有电影评论和情感注释，则您只能学习对电影评论的情感进行分类。 因此，数据可用性通常是此阶段的限制因素。 在许多情况下，您将不得不自己收集和注释新数据集（我们将在下一节中介绍）。\n",
    "\n",
    "* 您面临什么类型的机器学习任务？ 是二分类吗？ 多类分类？ 标量回归？ 矢量回归？ 多类、多标签分类？ 图像分割？ 排行？ 其他东西，比如聚类、生成或强化学习？ 在某些情况下，机器学习甚至可能不是理解数据的最佳方式，您应该使用其他方法，例如简单的老派统计分析。\n",
    "    * 照片搜索引擎项目是一个多类、多标签的分类任务。\n",
    "    * 垃圾邮件检测项目是一项二元分类任务。如果将“攻击性内容”设置为单独的类，则是三向分类任务。\n",
    "    * 音乐推荐引擎不是通过深度学习，而是通过矩阵分解（协同过滤）得到更好的处理。\n",
    "    * 信用卡欺诈检测项目是一个二元分类任务。\n",
    "    * 点击率预测项目是一个标量回归任务。\n",
    "    * 异常 cookie 检测是一项二元分类任务，但它也需要一个对象检测模型作为第一阶段，以便正确裁剪原始图像中的 cookie。请注意，称为“异常检测”的机器学习技术集不太适合这种环境！\n",
    "    * 从卫星图像中寻找新考古遗址的项目是一项图像相似度排序任务：您需要检索与已知考古遗址最相似的新图像。\n",
    "\n",
    "* 现有的解决方案是什么样的？ 也许您的客户已经有一个手工制作的算法来处理垃圾邮件过滤或信用卡欺诈检测——有很多嵌套的 if 语句。 也许目前有人负责手动处理所考虑的过程——监控饼干工厂的传送带并手动移除坏饼干，或者制作歌曲推荐播放列表以发送给喜欢特定艺术家的用户。 您应该确保了解哪些系统已经到位，以及它们是如何工作的。\n",
    "\n",
    "* 您是否需要处理特定的限制？ 例如，您可能会发现您正在为其构建垃圾邮件检测系统的应用程序经过严格的端到端加密，因此垃圾邮件检测模型必须存在于最终用户的手机上，并且必须是 在外部数据集上训练。 也许 cookie 过滤模型有这样的延迟限制，它需要在工厂的嵌入式设备上运行，而不是在远程服务器上运行。 您应该了解适合您的工作的完整背景。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "active-messenger",
   "metadata": {},
   "source": [
    "完成研究后，您应该知道您的输入将是什么，您的目标将是什么，以及问题对应的机器学习任务的广泛类型。 注意你在这个阶段所做的假设：\n",
    "* 您假设根据您的输入可以预测您的目标。\n",
    "* 您假设可用的（或您即将收集的）数据足以提供信息以了解输入和目标之间的关系。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "absent-phoenix",
   "metadata": {},
   "source": [
    "在你有一个工作模型之前，这些只是假设，等待验证或无效。 并非所有问题都可以通过机器学习解决； 仅仅因为您已经收集了输入 X 和目标 Y 的示例，并不意味着 X 包含足够的信息来预测 Y。例如，如果您试图根据股票最近的价格历史预测股票市场上的走势， 你不太可能成功，因为历史价格不包含太多的预测信息。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "further-timer",
   "metadata": {},
   "source": [
    "### 收集数据集"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "tight-excess",
   "metadata": {},
   "source": [
    "一旦您了解了任务的性质并知道您的输入和目标将是什么，就该进行数据收集了——这是大多数机器学习项目中最艰巨、最耗时、最昂贵的部分。\n",
    "* 照片搜索引擎项目要求您首先选择要分类的标签集——您确定 10,000 个常见图像类别。然后，您需要使用该集合中的标签手动标记数十万张过去用户上传的图像。\n",
    "* 对于聊天应用垃圾邮件检测项目，由于用户聊天是端到端加密的，因此您无法使用其内容来训练模型。您需要访问包含数万个公共社交媒体帖子的单独数据集，并手动将它们标记为垃圾邮件、攻击性内容或可接受的内容。\n",
    "* 对于音乐推荐引擎，您可以只使用用户的“喜欢”。不需要收集新数据。对于点击率预测项目也是如此：您有大量过去广告的点击率记录，可以追溯到几年前。\n",
    "* 对于 cookie-flag 模型，您需要在传送带上方安装摄像头以收集数万张图像，然后需要有人手动标记这些图像。知道怎么做的人目前在曲奇工厂工作——不过看起来难度不大，应该可以培训人去做。\n",
    "* 卫星图像项目将需要一个考古学家团队来收集现有感兴趣地点的数据库，并且对于每个站点，您需要找到在不同天气条件下拍摄的现有卫星图像。要获得一个好的模型，您将需要数千个不同的站点。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "peripheral-blake",
   "metadata": {},
   "source": [
    "您在第 5 章中了解到，模型的泛化能力几乎完全来自于它所训练的数据的属性——您拥有的数据点数量、标签的可靠性、特征的质量。 一个好的数据集是值得关注和投资的资产。 如果您有额外的 50 小时花在一个项目上，那么分配它们的最有效方法很可能是收集更多数据，而不是寻求增量建模改进。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "demonstrated-secretariat",
   "metadata": {},
   "source": [
    "数据比算法更重要的观点在谷歌研究人员 2009 年发表的一篇题为“数据的不合理有效性”的论文中最为著名（标题是对\n",
    "1960 年著名的书“自然科学中数学的不合理有效性”，由尤金·维格纳 (Eugene Wigner) 撰写）。 这是在深度学习流行之前，但值得注意的是，深度学习的兴起只会让数据变得更加重要。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "possible-priest",
   "metadata": {},
   "source": [
    "如果您正在进行监督学习，那么一旦您收集了输入（例如图像），您将需要它们（例如这些图像的标签）：您将训练模型预测的注释的目标。\n",
    "\n",
    "有时，可以自动检索注释——例如，在我们的音乐推荐任务或我们的点击率预测任务的情况下。 但通常，您必须手动注释数据。 这是一个劳动繁重的过程。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "excited-prayer",
   "metadata": {},
   "source": [
    "**投资数据标注基础设施**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "discrete-fundamental",
   "metadata": {},
   "source": [
    "您的数据注释过程将决定目标的质量，进而决定模型的质量。 仔细考虑您可用的选项：\n",
    "* 您应该自己注释数据吗？\n",
    "* 您是否应该使用像 Mechanical Turk 这样的众包平台来收集标签？\n",
    "* 您应该使用专业数据标签公司的服务吗？"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "black-saint",
   "metadata": {},
   "source": [
    "外包可能会为您节省时间和金钱，但会失去控制权。 使用诸如 Mechanical Turk 之类的东西可能很便宜并且可以很好地扩展，但是您的注释最终可能会非常嘈杂。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "comparative-probe",
   "metadata": {},
   "source": [
    "要选择最佳选项，请考虑您正在使用的约束条件：\n",
    "* 数据标注员是否需要成为主题专家，或者任何人都可以对数据进行注释？ 任何人都可以选择猫与狗图像分类问题的标签，但狗品种分类任务的标签需要专业知识。 同时，\n",
    "注释骨折的 CT 扫描几乎需要医学学位。\n",
    "* 如果标注数据需要专业知识，你能培训人们去做吗？ 如果没有，您如何获得相关专家的帮助？\n",
    "* 您自己了解专家提出注释的方式吗？ 如果你不这样做，你将不得不将你的数据集视为一个黑匣子，并且你将无法执行手动特征工程——这并不重要，但它可能会受到限制。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "proud-ballet",
   "metadata": {},
   "source": [
    "如果您决定在内部标记数据，请问问自己将使用什么软件来记录注释。 您可能需要自己开发该软件。 高效的数据注释软件将为您节省大量时间，因此值得在项目早期进行投资。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "marine-lightweight",
   "metadata": {},
   "source": [
    "**谨防非代表性数据**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "placed-publisher",
   "metadata": {},
   "source": [
    "机器学习模型只能理解与他们之前看到的相似的输入。 因此，用于训练的数据应该代表生产数据是至关重要的。 这种关注应该是您所有数据收集工作的基础。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "magnetic-committee",
   "metadata": {},
   "source": [
    "假设您正在开发一个应用程序，用户可以在其中对菜肴拍照以找出其名称。您使用来自美食家流行的图像共享社交网络的图片来训练模型。部署时间到了，来自愤怒用户的反馈开始涌现：您的应用 10 次中有 8 次答错。这是怎么回事？你在测试集上的准确率远远超过 90%！快速浏览用户上传的数据会发现，使用随机智能手机从随机餐厅上传的随机菜肴的移动图片与您训练模型的专业品质、光线充足、开胃的图片完全不同：您的训练数据不具有代表性的生产数据。这是一个大罪——欢迎使用机器\n",
    "学习地狱。\n",
    "\n",
    "如果可能，请直接从将使用您的模型的环境中收集数据。电影评论情绪分类模型应该用于新的 IMDB 评论，而不是 Yelp 餐厅评论，也不是 Twitter 状态更新。如果您想对推文的情绪进行评分，请从收集和注释实际推文开始 - 来自与您在生产中期望的用户相似的一组用户。如果无法对生产数据进行训练，请确保您完全了解您的训练数据和生产数据有何不同，并且您正在积极纠正这些差异。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "unexpected-clause",
   "metadata": {},
   "source": [
    "您应该注意的一个相关现象是概念漂移。在几乎所有现实世界的问题中，你都会遇到概念漂移，尤其是那些处理用户生成数据的问题。当生产数据的属性随时间发生变化时，就会发生概念漂移，导致模型精度逐渐下降。 2013 年训练的音乐推荐引擎在今天可能不是很有效。同样，您使用的 IMDB 数据集是在 2011 年收集的，与 2012 年的评论相比，用它训练的模型在 2020 年的评论中的表现可能不如 2012 年的评论，因为词汇、表达和电影类型随着时间的推移而演变。概念漂移在信用卡欺诈检测等对抗性环境中尤为严重，其中欺诈模式几乎每天都在变化。处理快速的概念漂移需要不断的数据收集、注释和模型再训练。\n",
    "\n",
    "请记住，机器学习只能用于记住训练数据中存在的模式。你只能认出你以前见过的东西。使用基于过去数据训练的机器学习来预测未来是假设未来的行为会像过去一样。情况往往并非如此。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "gorgeous-commissioner",
   "metadata": {},
   "source": [
    "**注：抽样偏差问题**\n",
    "> 非代表性数据的一个特别阴险和常见的情况是抽样偏差。 当您的数据收集过程与您试图预测的内容相互作用时，就会出现抽样偏差，从而导致测量结果有偏差。 一个著名的历史例子发生在 1948 年的美国总统大选中。 在选举之夜，芝加哥论坛报刊登了标题“杜威击败杜鲁门”。 第二天早上，杜鲁门成为了赢家。 《论坛报》的编辑相信电话调查的结果——但 1948 年的电话用户并不是随机的、具有代表性的投票人口样本。 他们更有可能变得更富有、更保守，并投票支持共和党候选人杜威。 如今，每一次电话调查都会考虑抽样偏差。 这并不意味着抽样偏差在政治民意调查中已成为过去——远非如此。 但与 1948 年不同的是，民意测验专家意识到这一点并采取措施加以纠正。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "responsible-redhead",
   "metadata": {},
   "source": [
    "![](https://tva1.sinaimg.cn/large/008i3skNgy1gsutnzom7ij318t0u0gso.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "featured-butter",
   "metadata": {},
   "source": [
    "### 了解您的数据"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "funky-regulation",
   "metadata": {},
   "source": [
    "将数据集视为黑盒是非常糟糕的做法。 在开始训练模型之前，您应该探索和可视化您的数据，以深入了解是什么使其具有预测性（这将为特征工程提供信息）并筛选潜在问题。\n",
    "* 如果您的数据包含图像或自然语言文本，请直接查看一些示例（及其标签）。\n",
    "* 如果您的数据包含数值特征，最好绘制特征值的直方图以了解所取值的范围和不同值的频率。\n",
    "* 如果您的数据包含位置信息，请将其绘制在地图上。是否出现任何清晰的模式？\n",
    "* 某些样本是否缺少某些特征的值？如果是这样，您需要在准备数据时处理此问题（我们将在下一节介绍如何执行此操作）。\n",
    "* 如果您的任务是分类问题，请打印数据中每个类的实例数。这些类的代表是否大致相同？如果不是，您将需要考虑这种不平衡。\n",
    "* 检查目标泄漏：数据中是否存在提供有关在生产中可能不可用的目标的信息的特征。如果您正在训练医疗记录模型以预测某人将来是否会接受癌症治疗，并且记录包含“此人已被诊断出患有癌症”的特征，那么您的目标正在被人为地泄露到您的数据中。始终问自己，您的数据中的每个特征是否都可以在生产中以相同的形式使用？"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "educational-disaster",
   "metadata": {},
   "source": [
    "### 选择衡量成功的标准"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "speaking-volunteer",
   "metadata": {},
   "source": [
    "要控制某事，您需要能够观察它。要在项目上取得成功，您必须首先定义成功的含义——准确度？准确率和召回率？客户保留率？您的成功指标将指导您在整个项目中做出的所有技术选择。它应该直接与您的更高级别目标保持一致，例如客户的业务成功。\n",
    "\n",
    "对于平衡分类问题，其中每个类别的可能性均等，接收器操作特征曲线下的准确度和面积 (ROC AUC) 是常用指标。对于类别不平衡问题、排名问题或多标签分类，您可以使用精度和召回率，以及加权形式的精度或 ROC AUC。必须定义自己的自定义指标来衡量成功的情况并不少见。要了解机器学习成功指标的多样性以及它们与不同问题领域的关系，浏览 Kaggle (kaggle.com) 上的数据科学竞赛会很有帮助；它们展示了广泛的问题和评估指标。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "domestic-reservation",
   "metadata": {},
   "source": [
    "## 开发模型"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "difficult-increase",
   "metadata": {},
   "source": [
    "一旦您知道如何衡量您的进度，您就可以开始模型开发。 大多数教程和研究项目都假设这是唯一的一步——跳过假设已经完成的问题定义和数据集收集，并跳过假设由其他人处理的模型部署和维护。 事实上，模型开发只是在机器学习的工作流程中，如果你问我，这还不是最困难的一步。 机器学习中最困难的事情是构建问题，以及收集、注释和清理数据。 所以振作起来，相比之下，接下来的事情会很容易！"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "least-increase",
   "metadata": {},
   "source": [
    "### 准备数据"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "previous-cutting",
   "metadata": {},
   "source": [
    "正如您之前了解到的，深度学习模型通常不会摄取原始数据。 数据预处理旨在使手头的原始数据更适合神经网络。 这包括矢量化、标准化或处理缺失值。 许多预处理技术是特定领域的（例如，特定于文本数据或图像数据）； 当我们在实际示例中遇到它们时，我们将在后面的章节中介绍它们。 现在，我们将回顾所有数据域共有的基础知识。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "informational-biodiversity",
   "metadata": {},
   "source": [
    "**矢量化**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "outside-stewart",
   "metadata": {},
   "source": [
    "神经网络中的所有输入和目标通常必须是浮点数据的张量（或者，在特定情况下，整数或字符串的张量）。 无论您需要处理什么数据（声音、图像、文本），您都必须首先将其转化为张量，这一步骤称为数据矢量化。 例如，在第 4 章的前两个文本分类示例中，我们从表示为整数列表（代表单词序列）的文本开始，我们使用单热编码将它们转换为数据张量。 在对数字进行分类和预测房价的示例中，float32 数据已经以矢量化形式出现，因此您可以跳过这一步。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "established-insert",
   "metadata": {},
   "source": [
    "**值归一化**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "worth-stanley",
   "metadata": {},
   "source": [
    "在第 2 章的 MNIST 数字分类示例中，您从编码为 0-255 范围内的整数的图像数据开始，对灰度值进行编码。在将此数据输入网络之前，您必须将其转换为 255 并除以 255，因此最终会得到 0-1 范围内的浮点 float32 值。类似地，在预测房价时，您从具有各种范围的特征开始——一些特征具有较小的浮点值，其他特征具有相当大的整数值。在将此数据输入网络之前，您必须独立对每个特征进行标准化，使其标准差为 1，均值为 0。\n",
    "\n",
    "通常，将具有相对较大值的神经网络数据（例如，多位整数，比网络权重采用的初始值大得多）或异构数据馈入神经网络是不安全的（例如，一个特征在 0-1 范围内而另一个特征在 100-200 范围内的数据）。这样做会触发大的梯度更新，从而阻止网络收敛。为了使您的网络更容易学习，您的数据应具有以下特征：\n",
    "* 取小值— 通常，大多数值应在 0-1 范围内。\n",
    "* 同质——也就是说，所有特征的值都应该在大致相同的范围内。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "extraordinary-sample",
   "metadata": {},
   "source": [
    "此外，以下更严格的规范化实践很常见并且可以提供帮助，尽管它并不总是必要的（例如，您在数字分类示例中没有这样做）：\n",
    "* 独立标准化每个特征，使其均值为 0。\n",
    "* 独立标准化每个特征，使其标准偏差为 1。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "conditional-wheat",
   "metadata": {},
   "source": [
    "使用 NumPy 数组很容易做到这一点："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "temporal-teacher",
   "metadata": {},
   "outputs": [],
   "source": [
    "x -= x.mean(axis=0)\n",
    "x /= x.std(axis=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "accepted-correlation",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 或者\n",
    "x = (x-x.mean(axis=0))/x.std(axis=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "julian-terror",
   "metadata": {},
   "source": [
    "**处理缺失值**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "enabling-garden",
   "metadata": {},
   "source": [
    "有时，您的数据中可能存在缺失值。 例如，在房价示例中，第一个特征（数据中索引 0 的列）是人均犯罪率。 如果此功能不适用于所有样本怎么办？ 然后你会在训练或测试数据中有缺失值。\n",
    "\n",
    "您可以完全放弃该功能，但您不一定必须这样做。\n",
    "* 如果特征是分类的，那么创建一个新的分类意味着“值丢失”是安全的。 该模型将自动学习这对于目标意味着什么。\n",
    "* 如果特征是数字特征，请避免输入像“0”这样的任意值，因为它可能会在由特征形成的潜在空间中产生不连续性，从而使在其上训练的模型难以泛化。 相反，请考虑用数据集中特征的平均值或中值替换缺失值。 您还可以训练一个模型来预测给定其他特征值的特征值。\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dense-method",
   "metadata": {},
   "source": [
    "请注意，如果您期望测试数据中缺少分类特征，但网络是在没有任何缺失值的数据上训练的，那么网络将不会学会忽略缺失值！ 在这种情况下，您应该人为地生成缺少条目的训练样本：多次复制一些训练样本，并删除一些您认为可能在测试数据中丢失的分类特征。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "inner-kingston",
   "metadata": {},
   "source": [
    "**选择评估协议**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "unknown-audit",
   "metadata": {},
   "source": [
    "正如您在前一章中了解到的，模型的目的是实现泛化，并且您在整个模型开发过程中做出的每个建模决策都将受到旨在衡量泛化性能的验证指标的指导。 您的验证协议的目标是准确估计您选择的成功指标（例如准确性）对实际生产数据的影响。 该过程的可靠性对于构建有用的模型至关重要。\n",
    "\n",
    "在第 5 章中，我们回顾了三种常见的评估协议：\n",
    "* 维护一个保留验证集——当你有大量数据时要走的路\n",
    "* 进行 K 折交叉验证——当您的样本太少而无法进行可靠验证时，这是正确的选择\n",
    "* 进行迭代 K 折验证——用于在可用数据很少时执行高度准确的模型评估"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "solid-viewer",
   "metadata": {},
   "source": [
    "只需选择其中之一。 在大多数情况下，第一个会工作得很好。 正如您之前了解到的，请始终注意验证集的代表性，并注意不要在训练集和验证集之间存在冗余样本。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "speaking-boards",
   "metadata": {},
   "source": [
    "## 击败基线"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "available-detail",
   "metadata": {},
   "source": [
    "当您开始研究模型本身时，您最初的目标是获得统计功效，正如您在第 5 章中看到的：即开发一个能够击败简单基线的小型模型。\n",
    "\n",
    "在这个阶段，您应该关注以下三个最重要的事情：\n",
    "* 特征工程——过滤掉信息不足的特征（特征选择），并利用您对问题的了解来开发可能有用的新特征。\n",
    "* 选择正确的架构先验：您将使用哪种类型的模型架构？ 一个密集连接的网络，一个卷积网络，一个循环神经网络，一个 Transformer？ 深度学习是完成任务的好方法，还是应该使用其他方法？\n",
    "* 选择一个足够好的训练配置——你应该使用什么损失函数？ 什么批量大小和学习率？"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "norman-break",
   "metadata": {},
   "source": [
    "> **注意：选择正确的损失函数**  \n",
    "通常不可能直接针对衡量问题成功的指标进行优化。 有时没有简单的方法可以将度量转换为损失函数； 毕竟，损失函数需要在给定小批量数据的情况下是可计算的（理想情况下，损失函数应该可以计算单个数据点）并且必须是可微的（否则，您不能使用反向传播来计算） 训练你的网络）。 例如，广泛使用的分类指标 ROC AUC 无法直接优化。 因此，在分类任务中，通常会针对 ROC AUC 的代理指标进行优化，例如交叉熵。 一般来说，您可以希望交叉熵越低，ROC AUC 越高。\n",
    "\n",
    "表 6.1 可以帮助您为一些常见问题类型选择最后一层激活和损失函数。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "assumed-garage",
   "metadata": {},
   "source": [
    "![](https://tva1.sinaimg.cn/large/008i3skNgy1gsvfos1b99j310a0g0dhw.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "annoying-drama",
   "metadata": {},
   "source": [
    "对于大多数问题，您可以从现有模板开始。 您不是第一个尝试构建垃圾邮件检测器、音乐推荐引擎或图像分类器的人。 确保研究现有技术，以确定最有可能在您的任务中表现良好的特征工程技术和模型架构。\n",
    "\n",
    "请注意，并非总是可以达到统计功效。 如果在尝试了多个合理的架构后仍无法超越简单的基线，则可能是输入数据中不存在您所问问题的答案。 请记住，您正在做出两个假设：\n",
    "* 您假设根据您的输入可以预测您的输出。\n",
    "* 您假设可用数据足以提供信息以了解输入和输出之间的关系。\n",
    "\n",
    "这些假设很可能是错误的，在这种情况下，您必须回到绘图板。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "virtual-heritage",
   "metadata": {},
   "source": [
    "### 放大：开发一个过拟合的模型"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "progressive-clause",
   "metadata": {},
   "source": [
    "一旦你获得了一个具有统计能力的模型，问题就变成了，你的模型是否足够强大？ 它是否有足够的层和参数来正确建模手头的问题？ 例如，逻辑回归模型对 MNIST 具有统计能力，但不足以很好地解决问题。 请记住，机器学习中的普遍张力介于优化和泛化之间； 理想的模型是处于欠拟合和过拟合之间的边界； 在产能不足和产能过剩之间。 要弄清楚这条边界在哪里，首先你必须越过它。\n",
    "\n",
    "要确定您需要多大的模型，您必须开发一个过拟合的模型。 这相当容易，正如您在第 5 章中学到的：\n",
    "* 添加图层。\n",
    "* 使图层更大。\n",
    "* 训练更多的epoch。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "legislative-recipe",
   "metadata": {},
   "source": [
    "始终监控训练损失和验证损失，以及您关心的任何指标的训练和验证值。 当您看到模型在验证数据上的性能开始下降时，您就实现了过度拟合。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "central-southeast",
   "metadata": {},
   "source": [
    "### 正则化和调整您的模型"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "martial-merchant",
   "metadata": {},
   "source": [
    "一旦您获得了统计能力并且能够过度拟合，您就知道自己走在正确的道路上。 此时，您的目标变成了最大化泛化性能。\n",
    "\n",
    "此阶段将花费最多时间：您将反复修改模型、训练它、评估验证数据（此时不是测试数据）、再次修改并重复，直到模型与它一样好 可以得到。 以下是您应该尝试的一些事情：\n",
    "* 尝试不同的架构； 添加或删除图层。\n",
    "* 添加dropout。\n",
    "* 如果您的模型较小，请添加 L1 或 L2 正则化。\n",
    "* 尝试不同的超参数（例如每层的单元数或优化器的学习率）以找到最佳配置。\n",
    "* 或者，迭代数据管理或特征工程：收集和注释更多数据，开发更好的特征，或删除似乎没有信息的特征。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "unnecessary-click",
   "metadata": {},
   "source": [
    "通过使用自动超参数调整软件（例如 KerasTuner），可以自动执行大部分工作。我们将在第 13 章中介绍这一点。\n",
    "\n",
    "请注意以下几点：每次使用来自验证过程的反馈来调整模型时，都会将有关验证过程的信息泄漏到模型中。重复几次，这是无害的；但是在多次迭代中系统地完成，它最终会导致您的模型过拟合验证过程（即使没有模型直接针对任何验证数据进行训练）。这使得评估过程不太可靠。\n",
    "\n",
    "一旦您开发出令人满意的模型配置，您就可以在所有可用数据（训练和验证）上训练您的最终生产模型，并在测试集上对其进行最后一次评估。如果结果证明在测试集上的性能明显比在验证数据上测得的性能差，这可能意味着您的验证程序毕竟不可靠，或者您在调整参数时开始过度拟合验证数据模型的。在这种情况下，您可能希望切换到更可靠的评估协议（例如迭代 Kfold 验证）。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "marked-luxury",
   "metadata": {},
   "source": [
    "## 部署您的模型"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "genetic-friday",
   "metadata": {},
   "source": [
    "您的模型已成功通过测试集的最终评估——它已准备好部署并开始其生产生活。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "documented-blood",
   "metadata": {},
   "source": [
    "### 向利益相关者解释您的工作并设定期望"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "retired-fiction",
   "metadata": {},
   "source": [
    "成功和客户信任是持续满足或超越人们的期望； 您提供的实际系统只是图片的一半。 另一半是在发布前设定适当的预期。\n",
    "\n",
    "非专家对 AI 系统的期望通常是不切实际的。 例如，他们可能期望系统“理解”它的任务，并且能够在任务的上下文中运用类似人类的常识。 为了解决这个问题，您应该考虑展示一些模型失败模式的示例（例如，展示错误分类的样本是什么样的，尤其是那些错误分类似乎令人惊讶的样本）。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "metropolitan-conjunction",
   "metadata": {},
   "source": [
    "他们还可能期望获得人类级别的绩效，尤其是对于以前由人处理的流程。 大多数机器学习模型，因为它们被（不完美地）训练来近似人类生成的标签，几乎没有达到目标。 您应该清楚地传达模型性能预期。 避免使用诸如“模型具有 98% 的准确率”（大多数人在心理上四舍五入为 100%）之类的抽象陈述，而更喜欢谈论例如假阴性率和假阳性率。 您可以说，“通过这些设置，欺诈检测模型的误报率为 5%，误报率为 2.5%。每天，平均有 200 个有效交易将被标记为欺诈并发送进行人工审查，并且 平均会漏掉 14 笔欺诈交易。平均可以正确捕获 266 笔欺诈交易”。 清楚地将模型的性能指标与业务目标联系起来。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ethical-mining",
   "metadata": {},
   "source": [
    "您还应该确保与利益相关者讨论关键启动参数的选择——例如，应该标记交易的概率阈值（不同的阈值会产生不同的假阴性和假阳性率）。 此类决策涉及权衡，只有深入了解业务背景才能处理。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "frequent-music",
   "metadata": {},
   "source": [
    "### 发布推理模型"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "planned-granny",
   "metadata": {},
   "source": [
    "当您到达可以保存训练模型的 Colab 笔记本时，机器学习项目并没有结束。 您很少将在训练期间操作的完全相同的 Python 模型对象投入生产。\n",
    "\n",
    "首先，您可能希望将模型导出到 Python 以外的其他内容：\n",
    "* 您的生产环境可能根本不支持 Python——例如，如果它是移动应用程序或嵌入式系统。\n",
    "* 如果应用程序的其余部分不是 Python（可能是 JavaScript、C++ 等），则使用 Python 为模型提供服务可能会导致大量开销。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "going-brave",
   "metadata": {},
   "source": [
    "其次，由于您的生产模型将仅用于输出预测（称为推理的阶段），而不是用于训练，因此您有空间执行各种优化，使模型更快并减少其内存占用。\n",
    "\n",
    "让我们快速浏览一下您可用的不同模型部署选项。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "treated-genealogy",
   "metadata": {},
   "source": [
    "**将模型部署为 REST API**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "biological-tonight",
   "metadata": {},
   "source": [
    "这可能是将模型转化为产品的常用方法：在服务器或云实例上安装 TensorFlow，并通过 REST API 查询模型的预测。 你可以建立自己的\n",
    "使用 Flask（或任何其他 Python 网络开发库）之类的东西为应用程序提供服务，或者使用 TensorFlow 自己的库将模型作为 API 传送，称为 TensorFlow Serving。 您可以使用 TensorFlow Serving (www.tensorflow.org/tfx/guide/serving) 在几分钟内部署 Keras 模型。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "regulated-wright",
   "metadata": {},
   "source": [
    "在以下情况下，您应该使用此部署设置：\n",
    "* 使用模型预测的应用程序将可以可靠地访问互联网（显然）。 例如，如果您的应用程序是一个移动应用程序，从远程 API 提供预测意味着该应用程序将无法在飞行模式或 低连接环境。\n",
    "* 该应用程序没有严格的延迟要求：请求、推理和应答往返通常需要大约 500 毫秒。\n",
    "* 为推理发送的输入数据不是高度敏感的：数据需要以解密的形式在服务器上可用，因为模型需要看到它（但请注意，您应该对 HTTP 请求使用 SSL 加密和 回答）。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "marked-system",
   "metadata": {},
   "source": [
    "例如，图像搜索引擎项目、音乐推荐系统、信用卡欺诈检测项目和卫星图像项目都非常适合通过 REST API 提供服务。\n",
    "\n",
    "将模型部署为 REST API 时的一个重要问题是，您是要自己托管代码，还是要使用完全托管的第三方云服务。 例如，Google 产品 Cloud AI Platform 可让您简单地将 TensorFlow 模型上传到 Google Cloud Storage (GCS)，并为您提供一个 API 端点来查询它。 它负责处理许多实际细节，例如批处理预测、负载平衡和缩放。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "qualified-charger",
   "metadata": {},
   "source": [
    "**在设备上部署模型**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "friendly-doubt",
   "metadata": {},
   "source": [
    "有时，您可能需要让模型运行在运行使用它的应用程序的同一台设备上——可能是智能手机、机器人上的嵌入式 ARM CPU 或微型设备上的微控制器。 例如，也许您已经看到了一台能够自动检测您指向的场景中的人和面孔的相机：这可能是一个直接在相机上运行的小型深度学习模型。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "canadian-cylinder",
   "metadata": {},
   "source": [
    "您应该在以下情况下使用此设置：\n",
    "* 您的模型具有严格的延迟限制或需要在低连接环境中运行。 如果您正在构建沉浸式增强现实应用程序，则查询远程服务器不是一个可行的选择。\n",
    "* 您的模型可以做得足够小，以便它可以在目标设备的内存和功率限制下运行（您可以使用 TensorFlow 模型优化工具包：来帮助解决这个问题）。\n",
    "* 获得尽可能高的准确度对于您的任务来说并不是关键任务：运行时效率和准确度之间总是存在权衡，因此内存和功率限制通常要求您发布一个不如最好的模型 你可以运行的模型\n",
    "大型 GPU。\n",
    "* 输入数据是严格敏感的，因此不应在远程服务器上解密。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "primary-chinese",
   "metadata": {},
   "source": [
    "例如，我们的垃圾邮件检测模型需要作为聊天应用程序的一部分在最终用户的智能手机上运行，因为消息是端到端加密的，因此远程托管的模型根本无法读取。 同样，坏 cookie 检测模型有严格的延迟限制，需要在工厂运行。 幸运的是，在这种情况下，我们没有任何功率或空间限制，因此我们实际上可以在 GPU 上运行模型。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "terminal-match",
   "metadata": {},
   "source": [
    "要在智能手机或嵌入式设备上部署 Keras 模型，您的首选解决方案是 TensorFlow Lite (www.tensorflow.org/lite)。 它是一种高效的设备端深度学习推理框架，可在 Android 和 iOS 智能手机以及基于 ARM64 的计算机、Raspberry Pi 或某些微控制器上运行。 它包含一个转换器，可以直接将您的 Keras 模型转换为 TensorFlow Lite 格式。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "former-granny",
   "metadata": {},
   "source": [
    "**在浏览器中部署模型**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "appointed-supply",
   "metadata": {},
   "source": [
    "深度学习通常用于基于浏览器或基于桌面的 JavaScript 应用程序。 虽然通常可以让应用程序通过 REST API 查询远程模型，但可能有模型直接在浏览器中运行，在用户的计算机上运行（如果可用，则利用 GPU 资源）的主要优势。\n",
    "\n",
    "在以下情况下使用此设置：\n",
    "* 您希望将计算卸载给最终用户，这可以显着降低服务器成本。\n",
    "* 输入数据需要保留在最终用户的计算机或手机上。 例如，在我们的垃圾邮件检测项目中，聊天应用程序的网页版和桌面版（已实现）作为用 JavaScript 编写的跨平台应用程序）应该使用本地运行的模型。\n",
    "* 您的应用程序具有严格的延迟限制：虽然在最终用户的笔记本电脑或智能手机上运行的模型可能比在您自己服务器上的大型 GPU 上运行的模型慢，但您没有额外的 100 毫秒网络往返时间。\n",
    "* 在下载并缓存模型后，您需要您的应用程序在没有连接的情况下继续工作。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "matched-accused",
   "metadata": {},
   "source": [
    "当然，只有当您的模型足够小，不会占用用户笔记本电脑或智能手机的 CPU、GPU 或 RAM 时，才应该使用此选项。 此外，由于整个模型都将下载到用户的设备上，因此您应该确保有关模型的任何信息都不需要保密。 请注意，给定经过训练的深度学习模型，通常可以恢复有关训练数据的一些信息：如果您的训练模型是针对敏感数据进行训练的，则最好不要公开。\n",
    "\n",
    "为了在 JavaScript 中部署模型，TensorFlow 生态系统包括 TensorFlow.js (www.tensorflow.org/js)，这是一个用于深度学习的 JavaScript 库，它实现了几乎所有 Keras API（它最初以工作名称 WebKeras 开发）作为 以及许多较低级别的 TensorFlow API。 您可以轻松地将保存的 Keras 模型导入 TensorFlow.js，以将其作为基于浏览器的 JavaScript 应用程序或桌面 Electron 应用程序的一部分进行查询。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "convinced-wealth",
   "metadata": {},
   "source": [
    "**推理模型优化**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "unlike-century",
   "metadata": {},
   "source": [
    "当部署在对可用功率和内存（智能手机和嵌入式设备）有严格限制的环境中或对于具有低延迟要求的应用程序时，优化推理模型尤为重要。 在将模型导入 TensorFlow.js 或将其导出到 TensorFlow Lite 之前，您应该始终寻求优化模型。\n",
    "\n",
    "您可以应用两种流行的优化技术：\n",
    "* 权重修剪：并非权重张量中的每个系数对预测的贡献都相同。 通过只保留最重要的参数，可以大大减少模型层中的参数数量。 这减少了模型的内存和计算占用空间，而性能指标的成本很小。 通过调整要应用的修剪量，您可以控制大小和准确性之间的权衡。\n",
    "* 权重量化：深度学习模型使用单精度浮点 (float32 ) 权重进行训练。 但是，可以对 8 位有符号  量化整数 (int8) 进行加权，以获得一个仅推理模型，该模型小四倍，但仍接近原始模型的  精度。\n",
    "\n",
    "TensorFlow 生态系统包括与 Keras API 深度集成的权重修剪和量化工具包 (www.tensorflow.org/model_optimization)。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "collected-processing",
   "metadata": {},
   "source": [
    "### 在野外监控您的模型"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "accredited-kazakhstan",
   "metadata": {},
   "source": [
    "您已导出推理模型，将其集成到您的应用程序中，并对生产数据进行了试运行——该模型的行为与您预期的完全一致。 您已经编写了单元测试以及日志记录和状态监控代码——完美。 现在，是时候按下红色的大按钮并部署到生产环境了。\n",
    "\n",
    "即使这不是结束。 一旦你部署了一个模型，你需要继续监控它的行为、它在新数据上的性能、它与应用程序其余部分的交互以及它的\n",
    "对业务指标的最终影响。\n",
    "* 部署新的音乐推荐系统后，用户对在线广播的参与度是上升还是下降？切换到新的点击率预测模型后，平均广告点击率是否有所增加？考虑使用随机 A/B 测试将模型本身的影响与其他变化隔离开来：一个案例子集应该通过新模型，而另一个控制子集应该坚持旧过程。一旦处理了足够多的案例，两者之间的结果差异很可能归因于模型。\n",
    "* 如果可能，定期对模型对生产数据的预测进行人工审核。通常可以重用与数据注释相同的基础设施：发送一部分生产数据进行手动注释，并将模型的预测与新注释进行比较。例如，您绝对应该为图像搜索引擎和坏 cookie 标记系统执行此操作。\n",
    "* 如果无法进行手动审核，请考虑替代评估途径，例如用户调查（例如，在垃圾邮件和攻击性内容标记系统的情况下）。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "clear-characterization",
   "metadata": {},
   "source": [
    "### 维护您的模型"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "sealed-detector",
   "metadata": {},
   "source": [
    "最后，没有模型可以永远持续下去。 您已经了解了概念漂移：随着时间的推移，您的生产数据的特征会发生变化，逐渐降低模型的性能和相关性。 您的音乐推荐系统的寿命将以周计算。 对于信用卡欺诈检测系统，需要几天时间。 对于图像搜索引擎来说，最好的情况是几年。\n",
    "\n",
    "一旦您的模型推出，您就应该准备好训练将取代它的下一代。 像这样：\n",
    "* 注意生产数据的变化。 新功能是否可用？ 您是否应该扩展或以其他方式编辑标签集？\n",
    "* 不断收集和注释数据，并随着时间的推移不断改进注释管道。 特别是，您应该特别注意收集对于当前模型来说似乎难以分类的样本——这些样本最有可能有助于提高性能。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "round-spider",
   "metadata": {},
   "source": [
    "机器学习的通用工作流程到此结束——有很多事情要记住。 成为专家需要时间和经验，但别担心，你已经比前几章更聪明了。 您现在已经熟悉了大局——机器学习项目所涉及的整个范围。 虽然本书的大部分内容都将重点放在模型开发部分，但您现在知道它只是整个工作流程的一部分。 始终牢记大局！"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "congressional-david",
   "metadata": {},
   "source": [
    "## 章节总结"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "sound-budget",
   "metadata": {},
   "source": [
    "* 当你开始一个新的机器学习项目时，首先要定义手头的问题：\n",
    "    * 了解您打算做什么的更广泛的背景——最终目标是什么，限制是什么？\n",
    "    * 收集和注释数据集； 确保您深入了解您的数据。\n",
    "    * 选择如何衡量您的问题是否成功——您将监控验证数据的哪些指标？\n",
    "* 一旦理解了问题并拥有合适的数据集，就可以开发一个模型：\n",
    "    * 准备数据。\n",
    "    * 选择您的评估协议：保留验证？ K折验证？ 您应该使用数据的哪一部分进行验证？\n",
    "    * 实现统计能力：击败一个简单的基线。\n",
    "    * 放大：开发一个可以过度拟合的模型。\n",
    "    * 根据模型的性能对模型进行正则化并调整其超参数\n",
    "    * 验证数据。 许多机器学习研究往往只关注这一步——但要牢记大局。\n",
    "* 当您的模型准备就绪并在测试数据上产生良好的性能时，就可以进行部署了：\n",
    "    * 首先，确保与利益相关者设定适当的期望。\n",
    "    * 优化用于推理的最终模型，并将模型发送到所选的部署环境——Web 服务器、移动设备、浏览器、嵌入式设备……\n",
    "    * 监控您的模型在生产中的性能并不断收集数据，以便您可以开发下一代模型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "magnetic-terry",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:tensorflow]",
   "language": "python",
   "name": "conda-env-tensorflow-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
